package com.pai4j.zwiki.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.pai4j.common.util.JsonUtil;
import com.pai4j.zwiki.domain.entity.ProjectAnalysisEntity;
import com.pai4j.zwiki.domain.entity.ZWikiTaskQueueEntity;
import com.pai4j.zwiki.dto.ProjectSubmitRequest;
import com.pai4j.zwiki.dto.ZWikiTaskMessage;
import com.pai4j.zwiki.enums.ZWikiTaskType;
import com.pai4j.zwiki.repository.ProjectAnalysisRepository;
import com.pai4j.zwiki.repository.ZWikiTaskQueueRepository;
import com.pai4j.zwiki.service.queue.ZWikiTaskProducer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * ZWiki任务队列服务
 * 核心服务：管理任务队列、调度任务执行、处理任务状态
 *
 * @author pai4j
 * @since 2025-10-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ZWikiTaskQueueService {

    private final ZWikiTaskQueueRepository taskQueueRepository;
    private final ProjectAnalysisRepository projectAnalysisRepository;
    private final ZWikiTaskProducer taskProducer;
    private final ZWikiNotificationService notificationService;
    private final ProjectAnalysisService projectAnalysisService;
    private final ThesisGenerationService thesisGenerationService;
    private final InteractiveThesisService interactiveThesisService;
    private final UserVipService userVipService;
    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 提交项目分析任务（使用队列）
     */
    @Transactional
    public String submitProjectAnalysisTask(ProjectSubmitRequest request, MultipartFile zipFile) {
        log.info("提交项目分析任务到队列: projectName={}, sourceType={}", 
                request.getProjectName(), request.getSourceType());

        // 1. 生成任务ID
        String taskId = UUID.randomUUID().toString();

        // 2. 准备任务数据
        Map<String, Object> taskData = new HashMap<>();
        taskData.put("request", request);
        taskData.put("hasZipFile", zipFile != null);
        if (zipFile != null) {
            taskData.put("fileName", zipFile.getOriginalFilename());
            taskData.put("fileSize", zipFile.getSize());
        }

        // 3. 获取用户VIP信息
        boolean isVip = userVipService.isVipUser(request.getUserId());
        Integer priority = determinePriority(request);
        
        // 3. 创建任务队列记录
        ZWikiTaskQueueEntity taskQueue = ZWikiTaskQueueEntity.builder()
                .taskId(taskId)
                .userId(request.getUserId())
                .taskType(ZWikiTaskType.PROJECT_ANALYSIS.getCode())
                .status("pending")
                .priority(priority)
                .taskData(JsonUtil.toJsonString(taskData))
                .build();

        taskQueueRepository.save(taskQueue);
        
        log.info("任务创建: taskId={}, userId={}, isVip={}, priority={}", 
                taskId, request.getUserId(), isVip, priority);

        // 4. 计算队列位置和预计等待时间
        Long queueSize = taskQueueRepository.countTotalQueuedTasks();
        Integer queuePosition = queueSize.intValue() + 1;
        Integer estimatedWaitTime = calculateEstimatedWaitTime(queuePosition);

        // 5. 发送入队通知
        notificationService.notifyTaskQueued(taskQueue, queuePosition, estimatedWaitTime);

        // 6. 发送任务消息到队列
        ZWikiTaskMessage taskMessage = ZWikiTaskMessage.builder()
                .taskId(taskId)
                .userId(request.getUserId())
                .taskType(ZWikiTaskType.PROJECT_ANALYSIS.getCode())
                .priority(taskQueue.getPriority())
                .taskData(JsonUtil.toJsonString(taskData))
                .timestamp(System.currentTimeMillis())
                .build();

        taskProducer.sendTask(taskMessage);

        log.info("项目分析任务已加入队列: taskId={}, position={}, estimatedWait={}min", 
                taskId, queuePosition, estimatedWaitTime);

        return taskId;
    }

    /**
     * 提交论文生成任务（使用队列）
     */
    @Transactional
    public String submitThesisGenerationTask(String analysisTaskId, String templatePath) {
        log.info("提交论文生成任务到队列: analysisTaskId={}", analysisTaskId);

        String taskId = UUID.randomUUID().toString();

        // 获取项目分析结果
        ProjectAnalysisEntity analysisEntity = projectAnalysisRepository.findByTaskId(analysisTaskId)
                .orElseThrow(() -> new RuntimeException("分析任务不存在"));

        Map<String, Object> taskData = new HashMap<>();
        taskData.put("analysisTaskId", analysisTaskId);
        taskData.put("templatePath", templatePath);
        taskData.put("projectName", analysisEntity.getProjectName());

        ZWikiTaskQueueEntity taskQueue = ZWikiTaskQueueEntity.builder()
                .taskId(taskId)
                .userId(analysisEntity.getUserId())
                .taskType(ZWikiTaskType.THESIS_GENERATION.getCode())
                .status("pending")
                .priority(5) // 论文生成优先级较高
                .taskData(JsonUtil.toJsonString(taskData))
                .build();

        taskQueueRepository.save(taskQueue);

        // 发送通知和消息
        Long queueSize = taskQueueRepository.countTotalQueuedTasks();
        notificationService.notifyTaskQueued(taskQueue, queueSize.intValue(), calculateEstimatedWaitTime(queueSize.intValue()));

        ZWikiTaskMessage taskMessage = ZWikiTaskMessage.builder()
                .taskId(taskId)
                .userId(analysisEntity.getUserId())
                .taskType(ZWikiTaskType.THESIS_GENERATION.getCode())
                .priority(5)
                .taskData(JsonUtil.toJsonString(taskData))
                .timestamp(System.currentTimeMillis())
                .build();

        taskProducer.sendTask(taskMessage);

        return taskId;
    }

    /**
     * 执行项目分析任务
     */
    @Transactional
    public void executeProjectAnalysisTask(String taskId) {
        log.info("开始执行项目分析任务: taskId={}", taskId);

        try {
            // 1. 更新任务状态为处理中
            ZWikiTaskQueueEntity taskQueue = taskQueueRepository.findByTaskId(taskId)
                    .orElseThrow(() -> new RuntimeException("任务不存在"));

            taskQueue.setStatus("processing");
            taskQueue.setStartedAt(LocalDateTime.now());
            taskQueueRepository.save(taskQueue);

            // 2. 发送开始处理通知
            notificationService.notifyTaskStarted(taskQueue);

            // 3. 解析任务数据
            Map<String, Object> taskData = JsonUtil.fromJson(taskQueue.getTaskData(), Map.class);
            ProjectSubmitRequest request = objectMapper.convertValue(taskData.get("request"), ProjectSubmitRequest.class);

            // 4. 执行实际的分析任务（委托给ProjectAnalysisService）
            ProjectAnalysisEntity analysisEntity = createAnalysisEntity(taskId, request);
            projectAnalysisRepository.save(analysisEntity);

            // 5. 执行分析步骤（同步执行，因为已经在队列消费者线程中）
            if ("github".equals(request.getSourceType())) {
                projectAnalysisService.executeAnalysisAsync(taskId);
            } else if ("zip".equals(request.getSourceType())) {
                // ZIP文件处理需要特殊处理（从临时存储中获取）
                // 这里简化处理，实际需要实现文件缓存机制
                log.warn("ZIP文件分析暂时需要直接调用，不通过队列");
            }

            // 6. 标记任务完成
            markTaskCompleted(taskId, "项目分析完成");

        } catch (Exception e) {
            log.error("执行项目分析任务失败: taskId={}", taskId, e);
            markTaskFailed(taskId, e.getMessage());
            throw e;
        }
    }

    /**
     * 执行论文生成任务
     */
    @Transactional
    public void executeThesisGenerationTask(String taskId) {
        log.info("开始执行论文生成任务: taskId={}", taskId);

        try {
            ZWikiTaskQueueEntity taskQueue = taskQueueRepository.findByTaskId(taskId)
                    .orElseThrow(() -> new RuntimeException("任务不存在"));

            taskQueue.setStatus("processing");
            taskQueue.setStartedAt(LocalDateTime.now());
            taskQueueRepository.save(taskQueue);

            notificationService.notifyTaskStarted(taskQueue);

            // 解析任务数据并执行
            Map<String, Object> taskData = JsonUtil.fromJson(taskQueue.getTaskData(), Map.class);
            String analysisTaskId = (String) taskData.get("analysisTaskId");
            String templatePath = (String) taskData.get("templatePath");

            // 获取分析结果
            ProjectAnalysisEntity analysisEntity = projectAnalysisRepository.findByTaskId(analysisTaskId)
                    .orElseThrow(() -> new RuntimeException("分析任务不存在"));

            // 执行论文生成
            // 这里需要准备必要的参数
            Map<String, Object> projectInfo = new HashMap<>();
            projectInfo.put("projectName", analysisEntity.getProjectName());
            projectInfo.put("totalFiles", analysisEntity.getTotalFiles());
            projectInfo.put("totalJavaFiles", analysisEntity.getJavaFiles());
            projectInfo.put("totalLines", analysisEntity.getTotalLines());

            String thesisPath = thesisGenerationService.generateThesis(
                    analysisTaskId, 
                    projectInfo, 
                    "架构总结", // 需要从分析结果中获取
                    new HashMap<>(), // 图表路径
                    templatePath
            );

            markTaskCompleted(taskId, "论文生成完成: " + thesisPath);

        } catch (Exception e) {
            log.error("执行论文生成任务失败: taskId={}", taskId, e);
            markTaskFailed(taskId, e.getMessage());
            throw e;
        }
    }

    /**
     * 执行论文优化任务
     */
    @Transactional
    public void executeThesisOptimizationTask(String taskId) {
        log.info("开始执行论文优化任务: taskId={}", taskId);

        try {
            ZWikiTaskQueueEntity taskQueue = taskQueueRepository.findByTaskId(taskId)
                    .orElseThrow(() -> new RuntimeException("任务不存在"));

            taskQueue.setStatus("processing");
            taskQueue.setStartedAt(LocalDateTime.now());
            taskQueueRepository.save(taskQueue);

            notificationService.notifyTaskStarted(taskQueue);

            // 实际的优化逻辑
            // ...

            markTaskCompleted(taskId, "论文优化完成");

        } catch (Exception e) {
            log.error("执行论文优化任务失败: taskId={}", taskId, e);
            markTaskFailed(taskId, e.getMessage());
            throw e;
        }
    }

    /**
     * 标记任务完成
     */
    @Transactional
    public void markTaskCompleted(String taskId, String result) {
        ZWikiTaskQueueEntity taskQueue = taskQueueRepository.findByTaskId(taskId)
                .orElseThrow(() -> new RuntimeException("任务不存在"));

        taskQueue.setStatus("completed");
        taskQueue.setTaskResult(result);
        taskQueue.setCompletedAt(LocalDateTime.now());
        taskQueueRepository.save(taskQueue);

        // 获取对应的分析实体并发送完成通知
        projectAnalysisRepository.findByTaskId(taskId).ifPresent(
                analysisEntity -> notificationService.notifyTaskCompleted(analysisEntity)
        );

        log.info("任务标记为完成: taskId={}", taskId);
    }

    /**
     * 标记任务失败
     */
    @Transactional
    public void markTaskFailed(String taskId, String errorMessage) {
        ZWikiTaskQueueEntity taskQueue = taskQueueRepository.findByTaskId(taskId)
                .orElseThrow(() -> new RuntimeException("任务不存在"));

        taskQueue.setStatus("failed");
        taskQueue.setErrorMessage(errorMessage);
        taskQueue.setRetryCount(taskQueue.getRetryCount() + 1);
        taskQueueRepository.save(taskQueue);

        // 判断是否需要重试
        if (taskQueue.getRetryCount() < taskQueue.getMaxRetryCount()) {
            log.info("任务将自动重试: taskId={}, retryCount={}", taskId, taskQueue.getRetryCount());
            // 重新提交到队列（延迟一段时间）
            retryTask(taskQueue);
        } else {
            log.error("任务达到最大重试次数，标记为最终失败: taskId={}", taskId);
            notificationService.notifyTaskFailed(taskQueue, errorMessage);
        }
    }

    /**
     * 重试失败的任务
     */
    private void retryTask(ZWikiTaskQueueEntity taskQueue) {
        try {
            taskQueue.setStatus("pending");
            taskQueueRepository.save(taskQueue);

            ZWikiTaskMessage taskMessage = ZWikiTaskMessage.builder()
                    .taskId(taskQueue.getTaskId())
                    .userId(taskQueue.getUserId())
                    .taskType(taskQueue.getTaskType())
                    .priority(taskQueue.getPriority() + 1) // 提高优先级
                    .taskData(taskQueue.getTaskData())
                    .timestamp(System.currentTimeMillis())
                    .build();

            taskProducer.sendTask(taskMessage);
        } catch (Exception e) {
            log.error("重试任务失败: taskId={}", taskQueue.getTaskId(), e);
        }
    }

    /**
     * 定时检查超时任务（每5分钟执行一次）
     */
    @Scheduled(fixedDelay = 300000)
    public void checkTimeoutTasks() {
        try {
            // 查找超过30分钟仍在处理的任务
            LocalDateTime timeoutThreshold = LocalDateTime.now().minusMinutes(30);
            List<ZWikiTaskQueueEntity> timeoutTasks = taskQueueRepository.findTimeoutProcessingTasks(timeoutThreshold);

            for (ZWikiTaskQueueEntity task : timeoutTasks) {
                log.warn("发现超时任务: taskId={}, startedAt={}", task.getTaskId(), task.getStartedAt());
                markTaskFailed(task.getTaskId(), "任务处理超时");
            }

            if (!timeoutTasks.isEmpty()) {
                log.info("处理了{}个超时任务", timeoutTasks.size());
            }
        } catch (Exception e) {
            log.error("检查超时任务失败", e);
        }
    }

    /**
     * 定时处理需要重试的任务（每10分钟执行一次）
     */
    @Scheduled(fixedDelay = 600000)
    public void processRetryableTasks() {
        try {
            List<ZWikiTaskQueueEntity> retryableTasks = taskQueueRepository.findRetryableTasks();

            for (ZWikiTaskQueueEntity task : retryableTasks) {
                log.info("自动重试任务: taskId={}, retryCount={}", task.getTaskId(), task.getRetryCount());
                retryTask(task);
            }

            if (!retryableTasks.isEmpty()) {
                log.info("重试了{}个失败任务", retryableTasks.size());
            }
        } catch (Exception e) {
            log.error("处理重试任务失败", e);
        }
    }

    /**
     * 查询用户的任务队列状态
     */
    public List<ZWikiTaskQueueEntity> getUserTaskQueue(Long userId) {
        return taskQueueRepository.findByUserIdOrderByCreatedAtDesc(userId);
    }

    /**
     * 查询任务队列状态
     */
    public ZWikiTaskQueueEntity getTaskQueueStatus(String taskId) {
        return taskQueueRepository.findByTaskId(taskId)
                .orElseThrow(() -> new RuntimeException("任务不存在"));
    }

    /**
     * 确定任务优先级（VIP增强版）
     */
    private Integer determinePriority(ProjectSubmitRequest request) {
        // 根据用户VIP等级确定优先级
        Integer vipPriority = userVipService.getUserPriority(request.getUserId());
        
        // 可以叠加其他因素
        // 例如：紧急任务+1，大项目-1等
        
        log.debug("用户优先级: userId={}, priority={}", request.getUserId(), vipPriority);
        return vipPriority;
    }

    /**
     * 计算预计等待时间（分钟）
     */
    private Integer calculateEstimatedWaitTime(Integer queuePosition) {
        if (queuePosition == null || queuePosition <= 0) {
            return 0;
        }
        
        // 假设每个任务平均处理时间为5分钟
        int avgProcessingTime = 5;
        
        // 假设有3个并发处理线程
        int concurrency = 3;
        
        int waitTime = (queuePosition / concurrency) * avgProcessingTime;
        
        return Math.max(1, waitTime);
    }

    /**
     * 创建分析实体
     */
    private ProjectAnalysisEntity createAnalysisEntity(String taskId, ProjectSubmitRequest request) {
        return ProjectAnalysisEntity.builder()
                .taskId(taskId)
                .userId(request.getUserId())
                .projectName(request.getProjectName())
                .repositoryUrl(request.getRepositoryUrl())
                .sourceType(request.getSourceType())
                .status("pending")
                .progress(0)
                .currentStep("等待开始")
                .hasCustomTemplate(request.getHasCustomTemplate() != null && request.getHasCustomTemplate())
                .build();
    }
}

